home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Sprite 1984 - 1993
/
Sprite 1984 - 1993.iso
/
src
/
kernel
/
dev
/
sun4.md
/
devMouse.c
< prev
next >
Wrap
C/C++ Source or Header
|
1992-12-18
|
19KB
|
727 lines
/*
* devMouse.c --
*
* This file implements the "mouse" device, which is used by
* window systems to find out about keyboard and mouse events.
*
* Copyright 1989 Regents of the University of California
* Permission to use, copy, modify, and distribute this
* software and its documentation for any purpose and without
* fee is hereby granted, provided that the above copyright
* notice appear in all copies. The University of California
* makes no representations about the suitability of this
* software for any purpose. It is provided "as is" without
* express or implied warranty.
*/
#ifndef lint
static char rcsid[] = "$Header: /cdrom/src/kernel/Cvsroot/kernel/dev/sun4.md/devMouse.c,v 9.10 91/10/18 01:21:45 dlong Exp $ SPRITE (Berkeley)";
#endif /* not lint */
#include <sprite.h>
#include <dev.h>
#include <devAddrs.h>
#include <dev/mouse.h>
#include <errno.h>
#include <mouse.h>
#include <fs.h>
#include <fsio.h>
#include <list.h>
#include <status.h>
#include <stdlib.h>
#include <timer.h>
#include <tty.h>
#include <ttyAttach.h>
#include <z8530.h>
#include <console.h>
#include <user/bstring.h>
#include <fsioDevice.h>
/*
* For synchronization, use devTty's monitor lock (this module is
* so closely intertwined with devTty.c that this is the only logical
* approach).
*/
#define LOCKPTR (&devTtyLock)
/*
* One of the structures below is dynamically allocated for each
* input event.
*/
typedef struct {
List_Links links; /* Pointers to next & previous items. */
Mouse_Event event; /* Event. */
} Event;
static List_Links eventList; /* List of pending input events. */
static int listCount; /* Number of elements in list. */
#define MAX_LIST_LENGTH 500
/*
* Other information about mouse device. This file is strongly
* entwined with devTty.c in that this file only uses SOME of the
* devTty features (namely the ability to buffer input characters
* and process them at background level). The output portion of
* the mouse channel is not used: output on the mouse device goes
* to the keyboard channel.
*/
static DevTty mouseTty; /* Information used by devTty.c. */
static DevZ8530 mouse = { /* Information used by device driver. */
"mouse", /* name */
#ifdef sun4c
(DevZ8530Device *) NIL, /* address */
#else
(DevZ8530Device *) DEV_MOUSE_ADDR, /* address */
#endif
&mouseTty, /* ttyPtr */
#ifdef sun4c
0, /* vector */
#else
DEV_UART_VECTOR, /* vector */
#endif
1200, /* baud */
WRITE3_RX_8BIT, /* wr3 */
WRITE5_TX_8BIT, /* wr5 */
DevTtyInputChar, /* inputProc */
(ClientData) &mouseTty, /* inputData */
DevTtyOutputChar, /* outputProc */
(ClientData) &mouseTty, /* outputData */
0, /* oldRr0 */
Z_CHANNEL_B | Z_INACTIVE /* flags */
};
static Fs_NotifyToken token; /* Used for Fs call-backs to wake up
* waiting processes. */
static volatile int outputBuffer = -1; /* One-character output buffer shared
* without explicit synchronization
* between background and interrupt-
* level procedures. -1 means buffer
* empty; otherwise it contains a
* single character to be output. */
static DevZ8530 *keyboardPtr; /* Information about the keyboard's
* UART (needed to start up output). */
/*
* Forward declarations to procedures declared later in this file:
*/
static void MouseDelayedClose _ARGS_((ClientData clientData,
Proc_CallInfo *callInfoPtr));
static void MouseInputProc _ARGS_((ClientData dummy, int value));
static void KbdInputProc _ARGS_((ClientData dummy, int value));
static int MouseOutputProc _ARGS_((void));
/*
*----------------------------------------------------------------------
*
* DevMouseInit --
*
* Called during bootstrapping to initialize mouse-related
* things.
*
* Results:
* None.
*
* Side effects:
* Resets the serial device.
*
*----------------------------------------------------------------------
*/
void
#ifdef sun4c
DevMouseInit(virtAddr, vector)
DevZ8530Device *virtAddr;
int vector;
#else
DevMouseInit()
#endif
{
#ifdef sun4c
mouse.address = virtAddr;
mouse.vector = vector;
#endif
DevZ8530RawProc((Address)&mouse, TD_RAW_SHUTDOWN, 0, (char *) NULL,
0, (char *) NULL);
}
/*
*----------------------------------------------------------------------
*
* DevMouseOpen --
*
* Called through devFsOpTable to open the mouse device.
* Initializes the device and activates it so that it's ready
* to return input.
*
* Results:
* A standard Sprite ReturnStatus.
*
* Side effects:
* The mouse-related devices will be "turned on" if they aren't
* already, which may involve setting up interrupt handlers.
*
*----------------------------------------------------------------------
*/
/* ARGSUSED */
ENTRY ReturnStatus
DevMouseOpen(devicePtr, useFlags, notifyToken, flagsPtr)
Fs_Device *devicePtr; /* Information about device (e.g. type
* and unit number). */
int useFlags; /* Flags for the stream being opened:
* OR'ed combination of FS_READ and
* FS_WRITE. */
Fs_NotifyToken notifyToken; /* Used for Fs call-back to notify waiting
* processes that the terminal is ready. */
int *flagsPtr; /* OUT: Device IO flags */
{
if (devicePtr->unit != 0) {
return Compat_MapToSprite(ENXIO);
}
LOCK_MONITOR;
mouseTty.openCount += 1;
if (mouseTty.openCount == 1) {
token = notifyToken;
keyboardPtr = DevGrabKeyboard(KbdInputProc, (ClientData) 0,
MouseOutputProc, (ClientData) 0);
mouseTty.insertOutput = 0;
mouseTty.extractOutput = 0;
mouseTty.rawProc = DevZ8530RawProc;
mouseTty.activateProc = DevZ8530Activate;
mouseTty.rawData = (ClientData) &mouse;
mouseTty.inputProc = MouseInputProc;
mouseTty.inputData = 0;
mouseTty.consoleFlags = 0;
List_Init(&eventList);
(*mouseTty.activateProc)(&mouse);
}
UNLOCK_MONITOR;
return SUCCESS;
}
/*
*----------------------------------------------------------------------
*
* DevMouseRead --
*
* Called through devFsOpTable to read from the mouse device.
*
* Results:
* A standard Sprite ReturnStatus. Characters are stored at
* *readPtr->buffer, and the fields of *replyPtr are modified
* to describe what happened. The mouse must be read in even
* multiples of the size of Mouse_Event.
*
* Side effects:
* Information may be removed from the mouse input queue.
*
*----------------------------------------------------------------------
*/
/* ARGSUSED */
ENTRY ReturnStatus
DevMouseRead(devicePtr, readPtr, replyPtr)
Fs_Device *devicePtr; /* Information about device. */
register Fs_IOParam *readPtr; /* Input parameters. */
register Fs_IOReply *replyPtr; /* Place to store return information. */
{
int stillToDo;
char *bufPtr;
replyPtr->length = 0;
stillToDo = readPtr->length;
bufPtr = (char *) readPtr->buffer;
/*
* Make sure the buffer is large enough to hold at least one
* event.
*/
if (stillToDo < sizeof(Mouse_Event)) {
return Compat_MapToSprite(EINVAL);
}
LOCK_MONITOR;
if (List_IsEmpty(&eventList)) {
UNLOCK_MONITOR;
return Compat_MapToSprite(EWOULDBLOCK);
}
while ((stillToDo >= sizeof(Mouse_Event)) && !List_IsEmpty(&eventList)) {
register Event *eventPtr;
eventPtr = (Event *) List_First(&eventList);
List_Remove(&eventPtr->links);
bcopy((char *) &eventPtr->event, (char *) bufPtr, sizeof(Mouse_Event));
bufPtr += sizeof(Mouse_Event);
stillToDo -= sizeof(Mouse_Event);
replyPtr->length += sizeof(Mouse_Event);
free((char *) eventPtr);
listCount -= 1;
}
UNLOCK_MONITOR;
return SUCCESS;
}
/*
*----------------------------------------------------------------------
*
* DevMouseWrite --
*
* Called through devFsOpTable to write to the mouse device.
*
* Results:
* A standard Sprite ReturnStatus. Fields of *replyPtr are
* modified to indicate what happened in the write operation.
*
* Side effects:
* Information may be added to the output buffer for the keyboard.
*
*----------------------------------------------------------------------
*/
/* ARGSUSED */
ReturnStatus
DevMouseWrite(devicePtr, writePtr, replyPtr)
Fs_Device *devicePtr; /* Information about device. */
register Fs_IOParam *writePtr; /* Input parameters. */
register Fs_IOReply *replyPtr; /* Place to store result info. */
{
ReturnStatus status = SUCCESS;
int stillToDo;
char *bufPtr;
LOCK_MONITOR;
replyPtr->length = 0;
stillToDo = writePtr->length;
bufPtr = (char *) writePtr->buffer;
while (stillToDo != 0) {
if (outputBuffer != -1) {
status = FS_WOULD_BLOCK;
break;
}
outputBuffer = (*((char *) bufPtr)) & 0xff;
bufPtr++;
stillToDo--;
replyPtr->length++;
DevZ8530RawProc(keyboardPtr, TD_RAW_OUTPUT_READY, 0, (char *) NIL,
0, (char *) NIL);
}
UNLOCK_MONITOR;
return status;
}
/*
*----------------------------------------------------------------------
*
* DevMouseIOControl --
*
* Called through devFsOpTable to perform IOControl operations on
* the mouse device.
*
* Results:
* A standard Sprite ReturnStatus.
*
* Side effects:
* None.
*
*----------------------------------------------------------------------
*/
/* ARGSUSED */
ReturnStatus
DevMouseIOControl(devicePtr, iocPtr, replyPtr)
Fs_Device *devicePtr; /* Information about device. */
Fs_IOCParam *iocPtr; /* Parameter information (buffer sizes
* etc.). */
Fs_IOReply *replyPtr; /* Place to store result information. */
{
return Compat_MapToSprite(ENOTTY);
}
/*
*----------------------------------------------------------------------
*
* DevMouseSelect --
*
* Called through devFsOpTable to perform select-related functions
* on the mouse device.
*
* Results:
* Always SUCCESS. The values at *readPtr, *writePtr, and *exceptPtr
* get set to zero if the device is NOT readable, or writable, or
* exception-pending, respectively.
*
* Side effects:
* None.
*
*----------------------------------------------------------------------
*/
/* ARGSUSED */
ENTRY ReturnStatus
DevMouseSelect(devicePtr, readPtr, writePtr, exceptPtr)
Fs_Device *devicePtr; /* Information about device. */
int *readPtr; /* Set to zero if device not readable. */
int *writePtr; /* Set to zero if device not writable. */
int *exceptPtr; /* Set to zero if no exception pending on
* device. */
{
LOCK_MONITOR;
if (List_IsEmpty(&eventList)) {
*readPtr = 0;
}
if (outputBuffer != -1) {
*writePtr = 0;
}
*exceptPtr = 0;
UNLOCK_MONITOR;
return SUCCESS;
}
/*
*----------------------------------------------------------------------
*
* DevMouseClose --
*
* Called through devFsOpTable when the mouse device is closed.
*
* Results:
* A standard Sprite return status.
*
* Side effects:
* Data structures get cleaned up and possibly deallocated.
*
*----------------------------------------------------------------------
*/
/* ARGSUSED */
ReturnStatus
DevMouseClose(devicePtr, useFlags, openCount, writerCount)
Fs_Device *devicePtr; /* Information about device. */
int useFlags; /* Indicates whether stream being
* closed was open for reading and/or
* writing: OR'ed combination of
* FS_READ and FS_WRITE. */
int openCount; /* # of opens still active for this
* device. */
int writerCount; /* # of active opens that permit
* writing. */
{
LOCK_MONITOR;
mouseTty.openCount -= 1;
if (mouseTty.openCount == 0) {
while (!List_IsEmpty(&eventList)) {
List_Links *eventPtr;
eventPtr = List_First(&eventList);
List_Remove(eventPtr);
free((char *) eventPtr);
}
/*
* If I/O is still in progress, delay shutting down the device
* until the I/O completes.
*/
if (outputBuffer == -1) {
DevReleaseKeyboard();
(void) (*mouseTty.rawProc)(mouseTty.rawData, TD_RAW_SHUTDOWN, 0,
(char *) NULL, 0, (char *) NULL);
}
}
UNLOCK_MONITOR;
return SUCCESS;
}
/*
*----------------------------------------------------------------------
*
* MouseDelayedClose --
*
* Background-level procedure to complete the device close if
* it couldn't be completed at close-time because I/O was still
* in progress.
*
* Results:
* None.
*
* Side effects:
* The mouse gets shutdown and the keyboard reverts to normal
* operation.
*
*----------------------------------------------------------------------
*/
/*ARGSUSED*/
static void
MouseDelayedClose(clientData, callInfoPtr)
ClientData clientData; /* Not used. */
Proc_CallInfo *callInfoPtr; /* Not used. */
{
LOCK_MONITOR;
if (mouseTty.openCount == 0) {
DevReleaseKeyboard();
(void) (*mouseTty.rawProc)(mouseTty.rawData, TD_RAW_SHUTDOWN, 0,
(char *) NULL, 0, (char *) NULL);
}
UNLOCK_MONITOR;
}
/*
*----------------------------------------------------------------------
*
* DevMouseInterrupt --
*
* This procedure is invoked whenever an interrupt occurs
* for one of the Z8530 chips.
*
* Results:
* None.
*
* Side effects:
* The Z8530 interrupt handler gets invoked to see if anything
* happened related to the mouse UART.
*
*----------------------------------------------------------------------
*/
void
DevMouseInterrupt()
{
DevZ8530Interrupt((ClientData)&mouse);
}
/*
*----------------------------------------------------------------------
*
* MouseInputProc --
*
* This procedure is invoked at background level (i.e in a kernel
* process) to handle input characters from the mouse UART. The
* caller is expected to have acquired the tty monitor lock.
*
* Results:
* None.
*
* Side effects:
* The input character is converted to an event, which is then
* enqueued on an input queue.
*
*----------------------------------------------------------------------
*/
/* ARGSUSED */
INTERNAL static void
MouseInputProc(dummy, value)
ClientData dummy; /* Not used. */
int value; /* Character that arrived from UART. */
{
char c;
Time time;
Event *eventPtr;
/*
* Mouse characters arrive in bunches, with the first character
* of each bunch specially marked. A simple state machine here
* keeps track of where we are in the bunch.
*/
#define WAIT_SYNC 0
#define WAIT_DELTA_X1 1
#define WAIT_DELTA_Y1 2
#define WAIT_DELTA_X2 3
#define WAIT_DELTA_Y2 4
#define NUM_STATES 5
#define SYNC_BIT 0x80
static int curState = WAIT_SYNC;
static Mouse_Event event;
/*
* Discard any special characters (breaks, etc.).
*/
if (DEV_TTY_IS_CONTROL(value)) {
return;
}
c = value;
/*
* The check below keeps our state machine back in sync with the
* mouse by discarding characters up to the beginning of the next
* sequence.
*/
if ((curState == WAIT_SYNC) && !(c & SYNC_BIT)) {
return;
}
switch (curState) {
case WAIT_SYNC:
event.key = c & 0x7;
break;
case WAIT_DELTA_X1:
event.deltaX = (int) c;
break;
case WAIT_DELTA_Y1:
event.deltaY = (int) c;
break;
case WAIT_DELTA_X2:
event.deltaX += (int) c;
break;
case WAIT_DELTA_Y2:
event.deltaY += (int) c;
event.flags = MOUSE_EVENT;
Timer_GetRealTimeOfDay(&time, (int *) NIL, (Boolean *) NIL);
event.time = (time.seconds*1000) + (time.microseconds/1000);
eventPtr = (Event *) malloc(sizeof(Event));
List_InitElement(&eventPtr->links);
eventPtr->event = event;
List_Insert(&eventPtr->links, LIST_ATREAR(&eventList));
dev_LastConsoleInput = time;
Fsio_DevNotifyReader(token);
break;
}
curState++;
if (curState >= NUM_STATES) {
curState = 0;
}
}
/*
*----------------------------------------------------------------------
*
* KbdInputProc --
*
* This procedure is invoked at background level (i.e in a kernel
* process) to handle input characters from the keyboard UART.
* This procedure is invoked only when the mouse device is open.
* The caller is expected to have acquired the tty monitor lock.
*
* Results:
* None.
*
* Side effects:
* The input character is converted to an event, which is then
* enqueued on an input queue.
*
*----------------------------------------------------------------------
*/
/* ARGSUSED */
INTERNAL static void
KbdInputProc(dummy, value)
ClientData dummy; /* Not used. */
int value; /* Character that arrived from UART:
* identifies which key, and whether up
* or down transition. */
{
register Event *eventPtr;
Time time;
/*
* Throw away control events and anything corresponding to a console
* command.
*/
if (DEV_TTY_IS_CONTROL(value)) {
return;
}
if (DevConsoleConvertKeystroke(value) == -2) {
return;
}
eventPtr = (Event *) malloc(sizeof(Event));
List_InitElement(&eventPtr->links);
eventPtr->event.flags = KEYBOARD_EVENT;
if (value & 0x80) {
eventPtr->event.flags |= KEY_UP;
}
eventPtr->event.key = value & 0x7f;
eventPtr->event.deltaX = 0;
eventPtr->event.deltaY = 0;
Timer_GetRealTimeOfDay(&time, (int *) NIL, (Boolean *) NIL);
eventPtr->event.time = (time.seconds*1000) + (time.microseconds/1000);
List_Insert(&eventPtr->links, LIST_ATREAR(&eventList));
dev_LastConsoleInput = time;
Fsio_DevNotifyReader(token);
}
/*
*----------------------------------------------------------------------
*
* MouseOutputProc --
*
* This procedure is called at interrupt level to fetch the
* next output character for the mouse device (these output
* characters go to the keyboard).
*
* Results:
* Returns the next output character, or -1 if the output buffer
* is empty.
*
* Side effects:
* May wake up processes waiting to write to this device because
* the output buffer was full.
*
*----------------------------------------------------------------------
*/
static int
MouseOutputProc()
{
int result;
result = outputBuffer;
if (result != -1) {
outputBuffer = -1;
if (mouseTty.openCount > 0) {
Fsio_DevNotifyWriter(token);
} else {
Proc_CallFunc(MouseDelayedClose, (ClientData) NIL, 0);
}
}
return result;
}
/*
*----------------------------------------------------------------------
*
* Dev_ConsoleReset --
*
* This procedure is called as a console command procedure to
* switch console keyboard input back and forth between /dev/mouse
* and /dev/console.
*
* Results:
* None.
*
* Side effects:
* None.
*
*----------------------------------------------------------------------
*/
void
Dev_ConsoleReset(toConsole)
int toConsole; /* 1 means make keystrokes go to
* console. 0 means make keystrokes
* go to mouse device. */
{
if (toConsole) {
DevReleaseKeyboard();
} else {
keyboardPtr = DevGrabKeyboard(KbdInputProc, (ClientData) 0,
MouseOutputProc, (ClientData) 0);
}
}